# coding: utf-8

import json
from decimal import Decimal

from flask import request, views
from flask_jwt_extended import jwt_required

from exts import db, log, rdb
from server.apps.account.forms import AccTradeForm
from server.apps.account.models import AccBasic, AccTrade
from server.utils.IDCreator import IDCreator
from server.utils.restful import rest_success, rest_error


class AccBasicView(views.MethodView):
    def __init__(self):
        pass

    @jwt_required()
    def get(self):
        acc_id = request.args.get("acc_id")
        if acc_id:
            results = AccBasic.query.filter(AccBasic.acc_id == acc_id).all()
        else:
            results = AccBasic.query.all()
        if results:
            return rest_success("找到{}数据".format(len(results)), [x.dict_ for x in results])
        else:
            return rest_error("未找到数据")

    @staticmethod
    def post():  # 添加账户
        rdb_key = "acc_id"
        data = request.get_data().decode("utf-8")
        data = json.loads(data)
        acc_id = IDCreator.create_id(key=rdb_key, length=6)
        acc_info = AccBasic(acc_id=acc_id, **data)
        try:
            db.session.add(acc_info)
            db.session.commit()
            return rest_success("账户{name}添加成功".format(name=acc_info.name))
        except Exception as e:
            db.session.rollback()
            message = "账户{name}添加失败 {message}".format(name=acc_info.name, message=str(e))
            log.logger.error(message)
            return rest_error(message)


class AccTradeView(views.MethodView):
    """
    账户转账
    """
    rdb_key = "AccTrade"

    @classmethod
    def create_id(cls):
        return IDCreator.create_id(key=cls.rdb_key, year_related=True)

    @classmethod
    def post(cls):
        """
        账户交易
        """
        data = request.get_data().decode("utf-8")
        data = json.loads(data)
        form = AccTradeForm(**data)
        try:
            form.validate()
        except Exception as e:
            log.logger.error(str(e))
            return rest_error(str(e))
        data = form.data

        acc_id = data.get("acc_id")
        type_ = data.get("type_")  # 转入、转出、盈利、亏损、
        try:
            AccTradeView.check_acc_exist(acc_id)
        except Exception as e:
            log.logger.error(str(e))
            return rest_error(message=str(e))

        trade_id = cls.create_id()
        lock_in = rdb.lock(acc_id, blocking_timeout=5)
        try:
            error = None
            locked = lock_in.acquire()  # 加锁
            if not locked:
                raise Exception("账户{acc}加锁失败".format(acc=acc_id))
            params = {"acc_id": acc_id, "post_date": data.get("post_date"),
                      "type_": type_, "amount": data.get("amount")}
            if type_ in ["转入", "盈利"]:
                cls.increase_amount(trade_id=trade_id, params=params)
            elif type_ in ["转出", "亏损"]:
                cls.decrease_amount(trade_id=trade_id, params=params)
            db.session.commit()
        except Exception as e:
            error = e
            db.session.rollback()
            log.logger.error(str(e))

        if locked:
            lock_in.release()
        if error:
            return rest_error(str(error))
        return rest_success(message="交易成功")

    @staticmethod
    def check_acc_exist(acc_id):
        if not acc_id or acc_id == "":
            return None
        results = AccBasic.query.filter(AccBasic.acc_id == acc_id).all()
        if not results:
            raise Exception("账号{acc_id}不存在".format(acc_id=acc_id))

    @staticmethod
    def get():
        pass

    @classmethod
    def increase_amount(cls, params: dict, trade_id=None):
        if not trade_id:
            trade_id = cls.create_id()
        acc_id = params.get("acc_id")
        amount = params.get("amount")
        acc_basic = AccBasic.query.filter(AccBasic.acc_id == acc_id).first()
        acc_basic.balance += Decimal(amount)

        params["dc"] = "D"
        params["balance"] = acc_basic.balance
        acc_trade = AccTrade(trade_id=trade_id, **params)
        db.session.add(acc_trade)

    @classmethod
    def decrease_amount(cls, params: dict, trade_id=None):
        if not trade_id:
            trade_id = cls.create_id()
        acc_id = params.get("acc_id")
        amount = params.get("amount")
        acc_basic = AccBasic.query.filter(AccBasic.acc_id == acc_id).first()
        if acc_basic.balance < Decimal(amount).quantize(Decimal('0.00')):
            raise Exception("账户{acc_id}余额不足".format(acc_id=acc_id))
        acc_basic.balance -= Decimal(amount)

        params["dc"] = "C"
        params["balance"] = acc_basic.balance
        acc_trade = AccTrade(trade_id=trade_id, **params)
        db.session.add(acc_trade)
